<?php
/*
*用於開發者後臺的 擴展內容扩展 By yan
*/
namespace yan\googlesitemapgenerator;

use yii;
use yii\helpers\ArrayHelper;

use common\models\dao\ModuleConfig;

use frontend\components\CAction;

use frontend\models\Page;
use frontend\models\Config;

class Frontend extends CAction{
	private $buildOptions = array();
	public $options = array();
	public $simMode = false;
	public $configs = [];
    // 设置表
    public function run(){

    	$startTime = microtime(true);
        $startMemory = memory_get_peak_usage(true);
        //Do not index the actual XML pages, only process them.
		//This avoids that the XML sitemaps show up in the search results.
		if(!headers_sent()) header('X-Robots-Tag: noindex', true, 200);


        $query = ModuleConfig::find()->select(['value'])
                                ->where(['code'=>'googlesitemap', 'key'=>'content'])
                                ->asArray()->one();
        
        $this->configs = isset( $query['value'] ) ? json_decode($query['value'], true) : [];

        

        $allParams = Yii::$app->request->get('params');


		$type = $params = null;

		$allParams = empty($allParams) ? '' : ltrim($allParams, '-');

		if(strpos($allParams, "-") !== false) {
			$pa = explode('-', $allParams);
			$type = $pa['0'];

			$params = substr($allParams, strpos($allParams, "-") + 1);

		} else {
			$type = $allParams;
		}

		$html = false;

		$pack = false;
		$packed = false;

		if($pack) $packed = @ob_start('ob_gzhandler');

		$this->InitOptions();


		if($html) {
			ob_start();
		} else {
			header('Content-Type: text/xml; charset=utf-8');
		}

		if(!empty(Yii::$app->sitemapBuilder)){
			$mapbuilder = Yii::$app->sitemapBuilder;
		}else{
			$mapbuilder = new GoogleSitemapGeneratorStandardBuilder();
		}
		
		

		if(empty($allParams) || $allParams == "index") {

			$this->BuildSitemapHeader("sitemap"); //index

			$mapbuilder->Index($this);

			$this->BuildSitemapFooter("sitemap"); //index
		} else {
			

			$this->BuildSitemapHeader("sitemap");

			$mapbuilder->Content($this, $type, $params, $this->configs);

			$this->BuildSitemapFooter("sitemap");

			$this->AddEndCommend($startTime, Yii::$app->request->get(), $startMemory);
		}

		if($html) {
			$xmlSource = ob_get_clean();

			// Load the XML source
			$xml = new DOMDocument;
			$xml->loadXML($xmlSource);

			$xsl = new DOMDocument;
			$xsl->load($this->GetPluginPath() . "sitemap.xsl");

			// Configure the transformer
			$proc = new XSLTProcessor;
			$proc->importStyleSheet($xsl); // attach the xsl rules

			$domTranObj = $proc->transformToDoc($xml);

			// this will also output doctype and comments at top level
			foreach($domTranObj->childNodes as $node) echo $domTranObj->saveXML($node) . "\n";
		}

		if($packed) ob_end_flush();
		exit;
    }

    /**
	 * Returns the path to the directory where the plugin file is located
	 * @since 3.0b5
	 * @return string The path to the plugin directory
	 */
	public function GetPluginPath() {
		$path = dirname(__FILE__);
		return trailingslashit(str_replace("\\", "/", $path));
	}
    /**
	 * Generates the header for the sitemap with XML declarations, stylesheet and so on.
	 *
	 * @since 4.0
	 * @param string $format The format, either sitemap for a sitemap or index for the sitemap index
	 */
	private function BuildSitemapHeader($format) {

		if(!in_array($format, array("sitemap", "index"))) $format = "sitemap";

		$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<?xml version="1.0" encoding="UTF-8"' . '?' . '>'));

		$styleSheet = ($this->GetDefaultStyle() && $this->GetOption('b_style_default') === true
				? $this->GetDefaultStyle() : $this->GetOption('b_style'));

		if(!empty($styleSheet)) {
			$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<' . '?xml-stylesheet type="text/xsl" href="' . $styleSheet . '"?' . '>'));
		}

		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("sitemap-generator-url=\"http://www.arnebrachhold.de\" sitemap-generator-version=\"" . $this->GetVersion() . "\""));
		$this->AddElement(new GoogleSitemapGeneratorDebugEntry("generated-on=\"" . date("Y-m-d H:i" ) . "\""));

		switch($format) {
			case "sitemap":
				// $this->AddElement(new GoogleSitemapGeneratorXmlEntry('<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'));
				$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9" >'));
				break;
			case "index":
				$this->AddElement(new GoogleSitemapGeneratorXmlEntry('<sitemapindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'));
				break;
		}
	}

	/**
	 * Generates the footer for the sitemap with XML ending tag
	 *
	 * @since 4.0
	 * @param string $format The format, either sitemap for a sitemap or index for the sitemap index
	 */
	private function BuildSitemapFooter($format) {

		if(!in_array($format, array("sitemap", "index"))) $format = "sitemap";


		switch($format) {
			case "sitemap":
				$this->AddElement(new GoogleSitemapGeneratorXmlEntry('</urlset>'));
				break;
			case "index":
				$this->AddElement(new GoogleSitemapGeneratorXmlEntry('</sitemapindex>'));
				break;
		}
	}

	/**
	 * Outputs an element in the sitemap
	 *
	 * @since 3.0
	 * @param $page GoogleSitemapGeneratorXmlEntry The element
	 */
	public function AddElement($page) {

		if(empty($page)) return;
		echo $page->Render();
	}

	/**
	 * Adds information about time and memory usage to the sitemap
	 *
	 * @since 4.0
	 * @param float $startTime The microtime of the start
	 * @param int $startQueries
	 * @param int $startMemory
	 *
	 */
	private function AddEndCommend($startTime, $startQueries = 0, $startMemory = 0) {
		
	}
	/**
	 * Returns the URL to default XSLT style if it exists
	 * @since 3.0b5
	 * @return string The URL to the default stylesheet, empty string if not available.
	 */
	public function GetDefaultStyle() {
		$p = __DIR__;
		if(file_exists($p . "/sitemap.xsl")) {
			$url = SITE_URL . '/thirdpart/module/googlesitemapgenerator/';

			//If called over the admin area using HTTPS, the stylesheet would also be https url, even if the site frontend is not.
			// if( substr($url, 0, 5) == "https") $url = "https" . substr($url, 5);

			return $url . 'sitemap.xsl';
		}
		return '';
	}

	/**
	 * Returns the option value for the given key
	 *
	 * @since 3.0
	 * @param $key string The Configuration Key
	 * @return mixed The value
	 */
	public function GetOption($key) {
		$key = "sm_" . $key;
		if(array_key_exists($key, $this->options)) {
			return $this->options[$key];
		} else return null;
	}

	/**
	 * Sets up the default configuration
	 *
	 * @since 3.0
	 */
	public function InitOptions() {

		$this->options = array();
		$this->options["sm_b_prio_provider"] = "GoogleSitemapGeneratorPrioByCountProvider"; //Provider for automatic priority calculation
		$this->options["sm_b_ping"] = true; //Auto ping Google
		$this->options["sm_b_stats"] = false; //Send anonymous stats
		$this->options["sm_b_pingmsn"] = true; //Auto ping MSN
		$this->options["sm_b_autozip"] = true; //Try to gzip the output
		$this->options["sm_b_memory"] = ''; //Set Memory Limit (e.g. 16M)
		$this->options["sm_b_time"] = -1; //Set time limit in seconds, 0 for unlimited, -1 for disabled
		$this->options["sm_b_style_default"] = true; //Use default style
		$this->options["sm_b_style"] = ''; //Include a stylesheet in the XML
		$this->options["sm_b_baseurl"] = ''; //The base URL of the sitemap
		$this->options["sm_b_robots"] = true; //Add sitemap location to WordPress' virtual robots.txt file
		$this->options["sm_b_html"] = true; //Include a link to a html version of the sitemap in the XML sitemap
		$this->options["sm_b_exclude"] = array(); //List of post / page IDs to exclude
		$this->options["sm_b_exclude_cats"] = array(); //List of post / page IDs to exclude

		$this->options["sm_in_home"] = true; //Include homepage
		$this->options["sm_in_posts"] = true; //Include posts
		$this->options["sm_in_posts_sub"] = false; //Include post pages (<!--nextpage--> tag)
		$this->options["sm_in_pages"] = true; //Include static pages
		$this->options["sm_in_cats"] = false; //Include categories
		$this->options["sm_in_arch"] = false; //Include archives
		$this->options["sm_in_auth"] = false; //Include author pages
		$this->options["sm_in_tags"] = false; //Include tag pages
		$this->options["sm_in_tax"] = array(); //Include additional taxonomies
		$this->options["sm_in_customtypes"] = array(); //Include custom post types
		$this->options["sm_in_lastmod"] = true; //Include the last modification date

		$this->options["sm_cf_home"] = "daily"; //Change frequency of the homepage
		$this->options["sm_cf_posts"] = "monthly"; //Change frequency of posts
		$this->options["sm_cf_pages"] = "weekly"; //Change frequency of static pages
		$this->options["sm_cf_cats"] = "weekly"; //Change frequency of categories
		$this->options["sm_cf_auth"] = "weekly"; //Change frequency of author pages
		$this->options["sm_cf_arch_curr"] = "daily"; //Change frequency of the current archive (this month)
		$this->options["sm_cf_arch_old"] = "yearly"; //Change frequency of older archives
		$this->options["sm_cf_tags"] = "weekly"; //Change frequency of tags

		$this->options["sm_pr_home"] = 1.0; //Priority of the homepage
		$this->options["sm_pr_posts"] = 0.6; //Priority of posts (if auto prio is disabled)
		$this->options["sm_pr_posts_min"] = 0.2; //Minimum Priority of posts, even if autocalc is enabled
		$this->options["sm_pr_pages"] = 0.6; //Priority of static pages
		$this->options["sm_pr_cats"] = 0.3; //Priority of categories
		$this->options["sm_pr_arch"] = 0.3; //Priority of archives
		$this->options["sm_pr_auth"] = 0.3; //Priority of author pages
		$this->options["sm_pr_tags"] = 0.3; //Priority of tags

		$this->options["sm_i_donated"] = false; //Did you donate? Thank you! :)
		$this->options["sm_i_hide_donated"] = false; //And hide the thank you..
		$this->options["sm_i_install_date"] = time(); //The installation date
		$this->options["sm_i_hide_survey"] = false; //Hide the survey note
		$this->options["sm_i_hide_note"] = false; //Hide the note which appears after 30 days
		$this->options["sm_i_hide_works"] = false; //Hide the "works?" message which appears after 15 days
		$this->options["sm_i_hide_donors"] = false; //Hide the list of donations
		$this->options["sm_i_hash"] = substr(sha1(sha1(SITE_URL)),0,20); //Partial hash for GA stats, NOT identifiable!
		$this->options["sm_i_lastping"] = 0; //When was the last ping
		$this->options["sm_i_supportfeed"] = true; //shows the support feed
		$this->options["sm_i_supportfeed_cache"] = 0; //Last refresh of support feed
	}

	/**
	 * Returns the version of the generator
	 *
	 * @since 3.0
	 * @return int The version
	 */
	public static function GetVersion() {
		return '4.4.1';
	}

	/**
	 * Adds a url to the sitemap. You can use this method or call AddElement directly.
	 *
	 * @since 3.0
	 * @param $loc string The location (url) of the page
	 * @param $lastMod int The last Modification time as a UNIX timestamp
	 * @param $changeFreq string The change frequenty of the page, Valid values are "always", "hourly", "daily", "weekly", "monthly", "yearly" and "never".
	 * @param $priority float The priority of the page, between 0.0 and 1.0
	 * @param $postID int The post ID in case this is a post or page
	 * @see AddElement
	 * @return string The URL node
	 */
	public function AddUrl($loc, $lastMod = 0, $changeFreq = "monthly", $priority = 0.5, $postID = 0) {
		//Strip out the last modification time if activated
		if($this->GetOption('in_lastmod') === false) $lastMod = 0;
		$page = new GoogleSitemapGeneratorPage($loc, $priority, $changeFreq, $lastMod, $postID);

		if($this->simMode) {
			$caller = $this->GetExternalBacktrace(debug_backtrace());

			$this->simData["content"][] = array(
				"data" => $page,
				"caller" => $caller
			);
		} else {
			$this->AddElement($page);
		}
	}

	/**
	 * Add a sitemap entry to the index file
	 * @param $type
	 * @param string $params
	 * @param int $lastMod
	 */
	public function AddSitemap($type, $params = "", $lastMod = 0) {

		$url = $this->GetXmlUrl($type, $params);
		

		$sitemap = new GoogleSitemapGeneratorSitemapEntry($url, $lastMod);

		if($this->simMode) {
			$caller = $this->GetExternalBacktrace(debug_backtrace());
			$this->simData["sitemaps"][] = array("data" => $sitemap, "type" => $type, "params" => $params, "caller" => $caller);
		} else {
			$this->AddElement($sitemap);
		}
	}

	/**
	 * Returns the URL for the sitemap file
	 *
	 * @since 3.0
	 * @param string $type
	 * @param string $params
	 * @param array $buildOptions
	 * @return string The URL to the Sitemap file
	 */
	public function GetXmlUrl($type = "", $params = "", $buildOptions = array()) {

		$pl = true;
		$options = "";
		if(!empty($type)) {
			$options .= $type;
			if(!empty($params)) {
				$options .= "-" . $params;
			}
		}

		$buildOptions = array_merge($this->buildOptions, $buildOptions);

		$html = (isset($buildOptions["html"]) ? $buildOptions["html"] : false);
		$zip = (isset($buildOptions["zip"]) ? $buildOptions["zip"] : false);

		
		if( Yii::$app->language == 'en-US'){
			
			$baseURL = SITE_URL.'/en-US/';
		}else{
			$baseURL = SITE_URL.'/';
		}
		//Manual override for root URL
		$baseUrlSettings = $this->GetOption('b_baseurl');
		if(!empty($baseUrlSettings)) $baseURL = $baseUrlSettings;
		else if(defined("SM_BASE_URL") && SM_BASE_URL) $baseURL = SM_BASE_URL;

		return trailingslashit($baseURL) . "sitemap" . ($options ? "-" . $options : "") . ($html
					? ".html" : ".xml") . ($zip? ".gz" : "");
	}
}



/**
 * Represents an XML entry, like definitions
 * @author Arne Brachhold
 * @package sitemap
 * @since 3.0
 */
class GoogleSitemapGeneratorXmlEntry {

	protected $_xml;

	public function __construct($xml) {
		$this->_xml = $xml;
	}

	public function Render() {
		return $this->_xml;
	}
}

/**
 * Represents an comment
 * @author Arne Brachhold
 * @package sitemap
 * @since 3.0
 * @uses GoogleSitemapGeneratorXmlEntry
 */
class GoogleSitemapGeneratorDebugEntry extends GoogleSitemapGeneratorXmlEntry {

	public function Render() {
		return "<!-- " . $this->_xml . " -->\n";
	}
}	


class GoogleSitemapGeneratorStandardBuilder {

	/**
	 * Creates a new GoogleSitemapGeneratorStandardBuilder instance
	 */
	public function __construct() {

	}

	/**
	 * Generates the content of the requested sitemap
	 *
	 * @param $gsg GoogleSitemapGenerator
	 * @param $type String The type of the sitemap
	 * @param $params String Parameters for the sitemap
	 */
	public function Content($gsg, $type, $params, $settings=[]) {

		switch($type) {
			case "pt":
				$this->BuildPosts($gsg, $params, $settings);
				break;
			case "misc":
				$this->BuildMisc($gsg, $settings);
				break;
		}
	}

	/**
	 * Generates the content for the post sitemap
	 *
	 * @param $gsg GoogleSitemapGenerator
	 * @param $params string
	 */
	public function BuildPosts($gsg, $params, $settings=[]) {		

	}

	

	/**
	 * Generates the misc sitemap
	 *
	 * @param $gsg GoogleSitemapGenerator
	 */
	public function BuildMisc($gsg, $settings=[]) {		
      
	}


	public function Index($gsg){
		$this->BuildMisc($gsg, $gsg->configs);		
	}
}


/**
 * Represents an item in the sitemap
 * @author Arne Brachhold
 * @package sitemap
 * @since 3.0
 */
class GoogleSitemapGeneratorSitemapEntry {

	/**
	 * @var string $_url Sets the URL or the relative path to the site dir of the page
	 */
	protected $_url;

	/**
	 * @var int $_lastMod Sets the lastMod date as a UNIX timestamp.
	 */
	protected $_lastMod;

	/**
	 * Returns the URL of the page
	 *
	 * @return string The URL
	 */
	public function GetUrl() {
		return $this->_url;
	}

	/**
	 * Sets the URL of the page
	 *
	 * @param string $url The new URL
	 */
	public function SetUrl($url) {
		$this->_url = (string) $url;
	}

	/**
	 * Returns the last mod of the page
	 *
	 * @return int The lastmod value in seconds
	 */
	public function GetLastMod() {
		return $this->_lastMod;
	}

	/**
	 * Sets the last mod of the page
	 *
	 * @param int $lastMod The lastmod of the page
	 */
	public function SetLastMod($lastMod) {
		$this->_lastMod = intval($lastMod);
	}

	public function __construct($url = "", $lastMod = 0) {
		$this->SetUrl($url);
		$this->SetLastMod($lastMod);
	}

	public function Render() {

		if($this->_url == "/" || empty($this->_url)) return '';

		$r = "";
		$r .= "\t<sitemap>\n";
		$r .= "\t\t<loc>" . $this->EscapeXML( $this->_url ) . "</loc>\n";
		if($this->_lastMod > 0) $r .= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00', $this->_lastMod) . "</lastmod>\n";
		$r .= "\t</sitemap>\n";
		return $r;
	}

	protected function EscapeXML($string) {
		return str_replace(array('&', '"', "'", '<', '>'), array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'), $string);
	}
}

/**
 * Represents an item in the page list
 * @author Arne Brachhold
 * @package sitemap
 * @since 3.0
 */
class GoogleSitemapGeneratorPage {

	/**
	 * @var string $_url Sets the URL or the relative path to the site dir of the page
	 */
	public $_url;

	/**
	 * @var float $_priority Sets the priority of this page
	 */
	public $_priority;

	/**
	 * @var string $_changeFreq Sets the chanfe frequency of the page. I want Enums!
	 */
	public $_changeFreq;

	/**
	 * @var int $_lastMod Sets the lastMod date as a UNIX timestamp.
	 */
	public $_lastMod;

	/**
	 * @var int $_postID Sets the post ID in case this item is a WordPress post or page
	 */
	public $_postID;

	/**
	 * Initialize a new page object
	 *
	 * @since 3.0
	 * @param string $url The URL or path of the file
	 * @param float $priority The Priority of the page 0.0 to 1.0
	 * @param string $changeFreq The change frequency like daily, hourly, weekly
	 * @param int $lastMod The last mod date as a unix timestamp
	 * @param int $postID The post ID of this page
	 * @return GoogleSitemapGeneratorPage
	 *
	 */
	public function __construct($url = "", $priority = 0.0, $changeFreq = "never", $lastMod = 0, $postID = 0) {
		$this->SetUrl($url);
		$this->SetProprity($priority);
		$this->SetChangeFreq($changeFreq);
		$this->SetLastMod($lastMod);
		$this->SetPostID($postID);
	}

	/**
	 * Returns the URL of the page
	 *
	 * @return string The URL
	 */
	public function GetUrl() {
		return $this->_url;
	}

	/**
	 * Sets the URL of the page
	 *
	 * @param string $url The new URL
	 */
	public function SetUrl($url) {
		$this->_url = (string) $url;
	}

	/**
	 * Returns the priority of this page
	 *
	 * @return float the priority, from 0.0 to 1.0
	 */
	public function GetPriority() {
		return $this->_priority;
	}

	/**
	 * Sets the priority of the page
	 *
	 * @param float $priority The new priority from 0.1 to 1.0
	 */
	public function SetProprity($priority) {
		$this->_priority = floatval($priority);
	}

	/**
	 * Returns the change frequency of the page
	 *
	 * @return string The change frequncy like hourly, weekly, monthly etc.
	 */
	public function GetChangeFreq() {
		return $this->_changeFreq;
	}

	/**
	 * Sets the change frequency of the page
	 *
	 * @param string $changeFreq The new change frequency
	 */
	public function SetChangeFreq($changeFreq) {
		$this->_changeFreq = (string) $changeFreq;
	}

	/**
	 * Returns the last mod of the page
	 *
	 * @return int The lastmod value in seconds
	 */
	public function GetLastMod() {
		return $this->_lastMod;
	}

	/**
	 * Sets the last mod of the page
	 *
	 * @param int $lastMod The lastmod of the page
	 */
	public function SetLastMod($lastMod) {
		$this->_lastMod = intval($lastMod);
	}

	/**
	 * Returns the ID of the post
	 *
	 * @return int The post ID
	 */
	public function GetPostID() {
		return $this->_postID;
	}

	/**
	 * Sets the ID of the post
	 *
	 * @param int $postID The new ID
	 */
	public function SetPostID($postID) {
		$this->_postID = intval($postID);
	}

	public function Render() {

		if($this->_url == "/" || empty($this->_url)) return '';

		$r = "";
		$r .= "\t<url>\n";
		$r .= "\t\t<loc>" . $this->EscapeXML($this->_url) . "</loc>\n";
		if($this->_lastMod > 0) $r .= "\t\t<lastmod>" . date('Y-m-d\TH:i:s+00:00', $this->_lastMod) . "</lastmod>\n";
		if(!empty($this->_changeFreq)) $r .= "\t\t<changefreq>" . $this->_changeFreq . "</changefreq>\n";
		if($this->_priority !== false && $this->_priority !== "") $r .= "\t\t<priority>" . number_format($this->_priority, 1) . "</priority>\n";
		$r .= "\t</url>\n";
		return $r;
	}

	protected function EscapeXML($string) {
		return str_replace(array('&', '"', "'", '<', '>'), array('&amp;', '&quot;', '&apos;', '&lt;', '&gt;'), $string);
	}
}


function trailingslashit( $string ) {
	return untrailingslashit( $string ) . '/';
}
function untrailingslashit( $string ) {
	return rtrim( $string, '/\\' );
}